[alphaorderly] WEEK 05 Solutions#2758
Conversation
📊 alphaorderly 님의 학습 현황이번 주 제출 문제
누적 학습 요약
문제 풀이 현황
🤖 이 댓글은 GitHub App을 통해 자동으로 작성되었습니다. 🔢 API 사용량 (gpt-5-nano)
|
There was a problem hiding this comment.
Trie를 압축을 할수 있을거 같은데 좀 연구해볼 필요가 있겠네요
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
- 패턴: Greedy, Two Pointers
- 설명: 주가를 한 번의 순회로 최솟값과 최대 이익을 갱신하는 방식으로, 현재 가격과 최솟값의 차이로 이익을 업데이트합니다. 공간은 상수이고, 한 방향으로 진행하는 탐욕적 패턴에 속합니다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(1) |
피드백: 최적의 해를 얻으려면 현재까지의 최저가와 지금의 가격 차이를 비교해 최대 이익을 업데이트한다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
- 패턴: Greedy, Dynamic Programming, Hash Map / Hash Set, Divide and Conquer, Two Pointers, Sliding Window, Fast & Slow Pointers, BFS, DFS, Backtracking, Union Find, Trie, Bit Manipulation, Heap / Priority Queue, Binary Search, Monotonic Stack, Dynamic Programming
- 설명: 주요 아이디어는 문자열 리스트를 특정 포맷으로 인코딩/디코딩하는 방법을 구현한 점으로, 배열의 원소를 길이-prefixed 방식으로 구성하는 패턴은 문자열 분리/해석에 해당하는 비트/문자열 조작과 비슷합니다. 두 번째 구현은 길이 접두사 방식으로 디코딩하는 과정을 통해 순차적 문자열 파싱의 예를 보여줘, 문자열 파싱(해체)과 연결 과정을 포함합니다.
📊 시간/공간 복잡도 분석
ℹ️ 이 파일에는 2가지 풀이가 포함되어 있어 각각 분석합니다.
풀이 1: Codec.encode — Time: O(n) / Space: O(n)
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(n) |
피드백: 문자열 길이 정보를 이용해 구분자로 구분하므로 일반적으로 안전한 인코딩이 가능하다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 2: Codec.decode — Time: O(n) / Space: O(n)
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(n) |
피드백: 가독성과 안전성을 높인 인코딩 방식으로 동작한다. eval 제거가 핵심 개선이다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
- 패턴: Hash Map / Hash Set, Divide and Conquer
- 설명: 단어들을 키로 묶어 그룹화하는 흐름으로 해시 맵을 사용해 Anagram을 분류한다. 첫 번째 구현은 정렬된 문자열을 키로 사용하고, 두 번째 구현은 문자 빈도 수를 키로 사용해 같은 키의 단어들을 모아 리스트로 묶는다. 두 방식 모두 해시 맵 기반의 그룹화 패턴이다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(n * k log k) |
| Space | O(n * k) |
피드백: 두 구현 모두 애너그램을 그룹화하는 일반적인 방법이다. 카운트 벡터를 사용하는 방식은 정렬보다 일정하게 성능을 보인다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
- 패턴: Trie, Hash Map / Hash Set
- 설명: 코드는 접두사 트리(Trie) 구조를 사용해 단어 삽입, 부분 문자열 검색, 접두사 검색을 구현합니다. 각 문자 노드를 따라가며 탐색하는 방식으로 동작하며, 중첩 그래프 형태의 트리 구조를 활용합니다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(L) |
| Space | O(N) |
피드백: 트라이를 사용해 글자 단위로 탐색하는 표준 접근이다. 각 노드는 자식 맵을 가지며 종료 플래그로 단어를 표시한다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
- 패턴: Dynamic Programming, Trie, Depth-First Search
- 설명: 코드는 단어 나눔 문제를 DP(탐색과 Memoization), Bottom-up DP, 그리고 Trie를 활용한 DFS로 해결하는 다중 구현이 혼합되어 있습니다. 첫 번째/두 번째 함수는 DP 패턴, 세 번째는 Trie 기반의 DFS로 경계 위치를 탐색합니다.
📊 시간/공간 복잡도 분석
ℹ️ 이 파일에는 3가지 풀이가 포함되어 있어 각각 분석합니다.
풀이 1: Solution.wordBreak (top-down with memoization) — Time: O(k * n^2) / Space: O(n)
| 복잡도 | |
|---|---|
| Time | O(k * n^2) |
| Space | O(n) |
피드백: 메모이제이션으로 중복 탐색을 피하지만 worst-case 탐색은 여전히 비싸다. startsWith 호출은 비효율적일 수 있다.
개선 제안: 고려해볼 만한 대안: 단어 사전을 트라이에 넣고 시작 지점에서 가능한 끝 지점을 빠르게 찾는 방법으로 최악의 경우를 줄일 수 있다.
풀이 2: Solution.wordBreak (bottom-up DP) — Time: O(k * n^2) / Space: O(n)
| 복잡도 | |
|---|---|
| Time | O(k * n^2) |
| Space | O(n) |
피드백: 직관적인 DP 풀이로 구현이 명확하다. 다만 inner 루프를 최적화하면 성능이 개선될 여지가 있다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 3: Trie-based DFS wordBreak — Time: O(L + n^2) / Space: O(L + n)
| 복잡도 | |
|---|---|
| Time | O(L + n^2) |
| Space | O(L + n) |
피드백: 트라이를 활용해 가능한 분할 경로를 효율적으로 탐색한다. 최악의 경우 여전히 n^2의 탐색이 발생할 수 있다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
|
코드 내용에 대한 적절한 평가 혹은 질문 혹은 보완점 리뷰 부탁드리겠습니다. |
|
병합을 위해 승인 처리합니다. @DaleStudy 승인 |
|
@alphaorderly 앗, 죄송합니다. 답안 제출을 4주차 PR을 병합하다가 함께 일괄 병합이 되어버렸네요 😅 앞으로 이런 문제가 없도록 자동화 도구를 개선하겠습니다. |
|
네~! |
* week 1 * [alphaorderly] WEEK 02 Solutions * fix: description에 맞게 코드 수정 * fix: 좀 더 간결하게 수정 * [alphaorderly] WEEK 03 Solutions * fix: 불필요한 코드 삭제 * fix: 줄바꿈 린트 문제 수정 * [alphaorderly] WEEK 03 Solutions * fix: 린트 오류 수정 * fix: 파이썬 내장함수 사용 코드 추가 * fix: valid-palindrome 문제에 투포인터 구현 답안 추가 * fix: 로직 가독성 수정 * [alphaorderly] WEEK 04 Solutions - draft * fix: 코드 가독성 향상 * [alphaorderly] WEEK 05 Solutions * trie 사용한 풀이법 추가 * fix: 코드 체크 실패 개선 * 주석 개선
| def encode(self, strs: List[str]) -> str: | ||
| strs = [str(len(s)) + "_" + s for s in strs] | ||
| return "".join(strs) | ||
|
|
There was a problem hiding this comment.
각 문자열 길이가 0~200 이라 고정 길이 방식도 고려해볼 수 있을 것 같습니다. 데이터 패턴에 따라 1글자가 많으면 작성해주신 방식이 유리할 거 같고 3글자가 많으면 고정길이가 유리해서 trade-off는 있을 거 같아요.
파싱하는 로직에서는 고정 자리수를 쓰는게 더 간단해서 좀 더 유리할 것 같네요.
There was a problem hiding this comment.
맞아요, 고정길이 코드 하신거 보니까 훨씬 깔끔하긴 하더라구요!!
| def insert(self, target: int): | ||
| node = self |
There was a problem hiding this comment.
target의 타입이 잘못된 거 같습니다.
There was a problem hiding this comment.
그렇네요, 파이썬 타입 힌트는 강하게 묶여있지 않아서 실수를 자주 하게 되네요
| ans = [] | ||
| node = self | ||
|
|
||
| for i in range(start, len(target)): | ||
| ch = target[i] | ||
|
|
||
| if ch not in node.children: | ||
| return ans | ||
|
|
||
| node = node.children[ch] | ||
| if node.end: | ||
| ans.append(i + 1) | ||
|
|
||
| return ans |
There was a problem hiding this comment.
검색 대상인 target 문자열에서 start부터 보면서 trie에 들어간 문자열중에
start에서 시작하는 문자열중 prefix가 정확하게 일치하는 문자열에 한해
채웠다고 가정하고 다 채운 이후의 인덱스가 어디인지를 저장해요!
예를 들어 wordDict에 abc, teg가 있고
target이 strategy 이며 start가 4인 경우
teg가 4번 인덱스부터 시작할때 일치하기 때문에
4(t) 5(e) 6(g) 를 넘기고 그 다음 인덱스인 7이 들어갑니다.
| S = len(s) | ||
|
|
||
| dp = [0] * (S + 1) | ||
| dp[0] = 1 | ||
|
|
||
| for index in range(S + 1): | ||
| for word in wordDict: | ||
| W = len(word) |
There was a problem hiding this comment.
S, W 변수는 의미가 잘 안 드러나고 PEP 8 컨벤션이랑 달라서 가독성을 약간 떨어지게 하는 거 같습니다.
PEP 8 컨벤션에 맞추어 lowercase 를 사용하시는건 어떨까요? https://peps.python.org/pep-0008/#function-and-variable-names
There was a problem hiding this comment.
아하! 저는 neetcodeIO 를 예전에 엄청 오래 보면서 공부를 했었어서 배열의 길이를 상수 취급해서 대문자로 적는거에 너무 익숙해져서 그렇긴 하네요
한번 고려해보겠습니다!
| """ | ||
| class Solution: | ||
| def wordBreak(self, s: str, wordDict: List[str]) -> bool: | ||
| @lru_cache() |
There was a problem hiding this comment.
@lru_cache의 maxSize 기본값이 128인데 이것도 고려하셨을까요?
There was a problem hiding this comment.
넹 맞아요, 문자열의 길이상 괜찮을것 같다는 판단이였어요
There was a problem hiding this comment.
넹 맞아요, 문자열의 길이상 괜찮을것 같다는 판단이였어요
@alphaorderly 128개 외에 밀려나는 캐시는 재계산하면 된다로 해석하면 될까요?
저는 cache 데코레이터 사용했는데 성능 차이가 어느정도일까요
많이 배워갑니다👍
| return True if isPrefix else node.end | ||
|
|
||
| def startsWith(self, prefix: str) -> bool: | ||
| return self.search(word=prefix, isPrefix=True) |
답안 제출 문제
작성자 체크 리스트
In Review로 설정해주세요.검토자 체크 리스트
Important
본인 답안 제출 뿐만 아니라 다른 분 PR 하나 이상을 반드시 검토를 해주셔야 합니다!